package net.atos.java.example.boodschappen.persistence.impl;

import java.util.LinkedList;
import java.util.List;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import net.atos.java.example.boodschappen.model.Entity;
import net.atos.java.example.boodschappen.persistence.Repository;
import net.atos.java.example.boodschappen.server.persistence.PersistenceHelper;

/**
 * Implementeert een basis jdo repository.
 * 
 * @author Pal Hargitai
 * @param <Identifier> Entiteit identificatie.
 * @param <DomeinEntity> Domein type.
 * @param <PersistenteEntity> Persistent type.
 */
public abstract class AbstractJdoRepository<Identifier, DomeinEntity extends Entity<Identifier>, PersistenteEntity extends Entity<Identifier>> implements Repository<Identifier, DomeinEntity> {

	/** De persistente entiteit type. */
	private Class<PersistenteEntity> clazz;

	/**
	 * Bouwt de repository.
	 * @param clazz Het persistente entiteit type.
	 */
	protected AbstractJdoRepository(Class<PersistenteEntity> clazz) {
		this.clazz = clazz;
	}

	/**
	 * Vertaal een domein entiteit naar een persistente entiteit.
	 * @param entity De te vertalen entiteit.
	 * @param pm De persistence manager.
	 * @return De persistente entiteit.
	 */
	protected abstract PersistenteEntity convertToPersistent(DomeinEntity entity, PersistenceManager pm);

	/**
	 * Vertaal een persistente entiteit naar een domein entiteit.
	 * @param entity De te vertalen entiteit.
	 * @param pm De persistence manager.
	 * @return De domein entiteit.
	 */
	protected abstract DomeinEntity convertToDomain(PersistenteEntity entity, PersistenceManager pm);

	/** {@inheritDoc} */
	@Override
	public DomeinEntity ophalen(Identifier identificatie) {
		PersistenceManager pm = PersistenceHelper.getPersistenceManager();
		PersistenteEntity entity;
		DomeinEntity result;
		try {
			entity = pm.getObjectById(clazz, identificatie);
			result = convertToDomain(entity, pm);
		} finally {
			pm.close();
		}
		return result;
	}

	/** {@inheritDoc} */
	@Override
	public Identifier opslaan(DomeinEntity entiteit) {
		PersistenceManager pm = PersistenceHelper.getPersistenceManager();
		PersistenteEntity entity;
		try {
			entity = pm.makePersistent(convertToPersistent(entiteit, pm));
		} finally {
			pm.close();
		}
		return entity.getIdentificatie();
	}

	/** {@inheritDoc} */
	@Override
	public void bewerken(DomeinEntity entiteit) {
		PersistenceManager pm = PersistenceHelper.getPersistenceManager();
		try {
			pm.makePersistent(convertToPersistent(entiteit, pm));
		} finally {
			pm.close();
		}
	}

	/** {@inheritDoc} */
	@Override
	public void verwijderen(Identifier identificatie) {
		PersistenceManager pm = PersistenceHelper.getPersistenceManager();
		try {
			PersistenteEntity entity = pm.getObjectById(clazz, identificatie);
			pm.deletePersistent(entity);
		} finally {
			pm.close();
		}
	}

	/** {@inheritDoc} */
	@SuppressWarnings("unchecked")
	@Override
	public List<DomeinEntity> allenOphalen() {
		PersistenceManager pm = PersistenceHelper.getPersistenceManager();
		List<PersistenteEntity> entityList;
		List<DomeinEntity> resultList = new LinkedList<DomeinEntity>();
		try {
			Query query = pm.newQuery(clazz);
			entityList =  (List<PersistenteEntity>) query.execute();
			for (PersistenteEntity entity : entityList) {
				resultList.add(convertToDomain(entity, pm));
			}
		} finally {
			pm.close();
		}
		return resultList;
	}
}
